package mongo

import (
	"context"
	"errors"
	"log"

	"fmt"

	"github.com/qiniu/qmgo"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
)

var client *qmgo.Client = nil
var ctx context.Context = context.Background()
var mgoUrl string      // mongo连接字符串
var mgoDataBase string // 连接的库

func GetContext() context.Context {
	return ctx
}

func Connect(url string) error {
	// 连接数据库
	cli, err := qmgo.NewClient(ctx, &qmgo.Config{
		Uri: url,
	})

	if err != nil {
		log.Println(fmt.Sprintf("connect mongodb %s failed: %s", url, err.Error()))
		return err
	}
	client = cli
	log.Println(fmt.Sprintf("connect mongodb %s success", url))
	return nil
}

/*
获取集合
*/
func GetCollection(coll_name string) *qmgo.Collection {
	if client == nil {
		return nil
	}
	var collection *qmgo.Collection = client.Database(mgoDataBase).Collection(coll_name)
	return collection
}

/**
 * @brief: 设置配置
 */
func SetConfig(connString string, database string) {
	mgoUrl = connString
	mgoDataBase = database
	Connect(mgoUrl)
}

// 集合转换
func collectConvert(collect interface{}) *qmgo.Collection {
	var collection *qmgo.Collection
	_, ok := collect.(qmgo.Collection)
	if ok {
		collection = collect.(*qmgo.Collection)
	} else {
		collection = GetCollection(collect.(string))
	}
	return collection
}

/**
* 查找数据
* 参数：文档名称,查询条件,绑定数据,database
 */
func Find(collect interface{}, filter interface{}) qmgo.QueryI {
	collection := collectConvert(collect)
	if collection == nil {
		return nil
	}

	if filter == nil {
		filter = bson.M{}
	}

	query := collection.Find(ctx, filter)
	return query
}

func FindId(collect interface{}, object_id string, result interface{}) error {
	collection := collectConvert(collect)
	if collection == nil {
		return errors.New(fmt.Sprintf("FindId collection is nil"))
	}

	id, _ := primitive.ObjectIDFromHex(object_id)
	filter := bson.D{{"_id", id}}

	err := collection.Find(ctx, filter).One(result)
	if err != nil {
		return err
	}
	return nil
}

// 删除数据
func Remove(collect interface{}, filter interface{}) error {
	collection := collectConvert(collect)
	if collection == nil {
		return errors.New(fmt.Sprintf("Remove collection is nil"))
	}
	err := collection.Remove(ctx, filter)
	if err != nil {
		return err
	}
	return nil
}

// 删除数据(根据ObjectId)
func RemoveId(collect interface{}, object_id string) error {
	collection := collectConvert(collect)
	if collection == nil {
		return errors.New(fmt.Sprintf("RemoveId collection is nil"))
	}

	id, _ := primitive.ObjectIDFromHex(object_id)
	err := collection.RemoveId(ctx, id)
	if err != nil {
		return err
	}
	return nil
}

// 删除所有数据
func RemoveAll(collect interface{}, filter interface{}) (*qmgo.DeleteResult, error) {
	collection := collectConvert(collect)
	if collection == nil {
		return nil, errors.New(fmt.Sprintf("RemoveId collection is nil"))
	}
	result, err := collection.RemoveAll(ctx, filter)
	if err != nil {
		return nil, err
	}
	return result, nil
}

// 获取数据数量
func GetCount(collect interface{}, filter interface{}) (int64, error) {
	collection := collectConvert(collect)
	if collection == nil {
		return 0, errors.New(fmt.Sprintf("GetCount collection is nil"))
	}

	if filter == nil {
		filter = bson.M{}
	}

	count, err := collection.Find(ctx, filter).Count()
	return count, err
}

func UpdateOne(collect interface{}, filter interface{}, update interface{}) error {
	collection := collectConvert(collect)
	if collection == nil {
		return errors.New(fmt.Sprintf("UpdateOne collection is nil"))
	}

	if filter == nil {
		filter = bson.M{}
	}

	error := collection.UpdateOne(ctx, filter, update)
	return error
}

// 更新数据
func UpdateId(collect interface{}, object_id string, update interface{}) error {
	collection := collectConvert(collect)
	if collection == nil {
		return errors.New(fmt.Sprintf("UpdateByObjectId collection is nil"))
	}

	id, _ := primitive.ObjectIDFromHex(object_id)
	err := collection.UpdateId(ctx, id, update)
	return err
}

// 更新数据
func UpdateAll(collect interface{}, filter interface{}, update interface{}) (*qmgo.UpdateResult, error) {
	collection := collectConvert(collect)
	if collection == nil {
		return nil, errors.New(fmt.Sprintf("UpdateByObjectId collection is nil"))
	}

	result, err := collection.UpdateAll(ctx, filter, update)
	return result, err
}

// 添加数据(单条)
func InsertOne(collect interface{}, doc interface{}) (*qmgo.InsertOneResult, error) {
	collection := collectConvert(collect)
	if collection == nil {
		return nil, errors.New(fmt.Sprintf("UpdateByObjectId collection is nil"))
	}
	result, err := collection.InsertOne(ctx, doc)
	return result, err
}

// 添加数据(多条)
func InsertMany(collect interface{}, doc interface{}) (*qmgo.InsertManyResult, error) {
	collection := collectConvert(collect)
	if collection == nil {
		return nil, errors.New(fmt.Sprintf("UpdateByObjectId collection is nil"))
	}
	result, err := collection.InsertMany(ctx, doc)
	return result, err
}
